package com.wordplat.quickstart.xutils.common.task;


import com.wordplat.quickstart.xutils.common.Callback;

import ohos.eventhandler.EventRunner;

import java.util.concurrent.Executor;


/**
 * Created by wyouflf on 15/6/5.
 * 异步任务基类
 *
 * @param <ResultType> 任务返回值类型
 * @since 2021-05-08
 */
public abstract class AbsTask<ResultType> implements Callback.Cancelable {

    private TaskProxy taskProxy = null;
    private final Callback.Cancelable cancelHandler;

    private volatile boolean isCancelled = false;
    private volatile State state = State.IDLE;
    private ResultType result;

    /**
     * AbsTask
     */
    public AbsTask() {
        this(null);
    }

    /**
     * AbsTask
     *
     * @param cancelHandler
     */
    public AbsTask(Callback.Cancelable cancelHandler) {
        this.cancelHandler = cancelHandler;
    }

    /**
     * doBackground
     *
     * @return ResultType
     * @throws Throwable
     */
    protected abstract ResultType doBackground() throws Throwable;

    /**
     * onSuccess
     *
     * @param result
     */
    protected abstract void onSuccess(ResultType result);

    /**
     * onError
     *
     * @param ex
     * @param isCallbackError
     */
    protected abstract void onError(Throwable ex, boolean isCallbackError);

    /**
     * onWaiting
     */
    protected void onWaiting() {
    }

    /**
     * onStarted
     */
    protected void onStarted() {
    }

    /**
     * onUpdate
     *
     * @param flag
     * @param args
     */
    protected void onUpdate(int flag, Object... args) {
    }

    /**
     * onCancelled
     *
     * @param cex
     */
    protected void onCancelled(Callback.CancelledException cex) {
    }

    /**
     * onFinished
     */
    protected void onFinished() {
    }

    /**
     * getPriority
     *
     * @return Priority
     */
    public Priority getPriority() {
        return null;
    }

    /**
     * getExecutor
     *
     * @return Executor
     */
    public Executor getExecutor() {
        return null;
    }

    /**
     * EventRunner
     *
     * @return EventRunner
     */
    public EventRunner customLooper() {
        return null;
    }

    /**
     * update
     *
     * @param flag
     * @param args
     */
    protected synchronized final void update(int flag, Object... args) {
        if (taskProxy != null) {
            taskProxy.onUpdate(flag, args);
        }
    }

    /**
     * invoked via cancel()
     */
    protected void cancelWorks() {
    }

    /**
     * 取消任务时是否不等待任务彻底结束, 立即收到取消的通知.
     *
     * @return 是否立即响应取消回调
     */
    protected boolean isCancelFast() {
        return false;
    }

    @Override
    public synchronized final void cancel() {
        /**
         * LogUtil.e("图片请求abstask==="+isCancelled);
         */
        if (this.isCancelled) {
            return;
        }
        synchronized (this) {
            if (this.isCancelled) {
                return;
            }
            /**
             *  LogUtil.e("图片请求abstask1111==="+isCancelled);
             */
            this.isCancelled = true;
            cancelWorks();
            if (cancelHandler != null && !cancelHandler.isCancelled()) {
                cancelHandler.cancel();
            }
            if (this.state == State.WAITING || (this.state == State.STARTED && isCancelFast())) {
                if (taskProxy != null) {
                    taskProxy.onCancelled(new Callback.CancelledException("cancelled by user"));
                    taskProxy.onFinished();
                } else if (this instanceof TaskProxy) {
                    this.onCancelled(new Callback.CancelledException("cancelled by user"));
                    this.onFinished();
                }
            }
        }
    }

    @Override
    public final boolean isCancelled() {
        return isCancelled || state == State.CANCELLED
                || (cancelHandler != null && cancelHandler.isCancelled());
    }

    /**
     * isFinished
     *
     * @return isFinished
     */
    public final boolean isFinished() {
        return this.state.value() > State.STARTED.value();
    }

    public final State getState() {
        return state;
    }

    public final ResultType getResult() {
        return result;
    }

    /**
     * package
     *
     * @param state
     */
    void setState(State state) {
        this.state = state;
    }

    /**
     * package
     *
     * @param taskProxy
     */
    final synchronized void setTaskProxy(TaskProxy taskProxy) {
        this.taskProxy = taskProxy;
    }

    /**
     * package
     *
     * @param result
     */
    final void setResult(ResultType result) {
        this.result = result;
    }

    /**
     * State
     *
     * @since 2021-04-22
     */
    public enum State {
        /**
         * IDLE WAITING STARTED SUCCESS CANCELLED ERROR
         */
        IDLE(0), WAITING(1), STARTED(2), SUCCESS(3), CANCELLED(4), ERROR(5);
        private final int value;

        State(int value) {
            this.value = value;
        }

        /**
         * value
         *
         * @return int
         */
        public int value() {
            return value;
        }
    }
}
